home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
et
/
et3_0-a1.lha
/
et3
/
src
/
TextPainter.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-08-26
|
12KB
|
485 lines
#ifdef __GNUG__
#pragma implementation
#endif
#include "TextPainter.h"
#include "Class.h"
#include "Text.h"
#include "Font.h"
#include "WindowSystem.h"
#include "TextFormatter.h" // -> LineDesc
#include "Bitmap.h"
#include "Math.h"
extern bool gPrinting; // --> #include PrintManager.h
//---- output map for control characters --------------------------------------
static RGBColor *invisColor;
static Font *symbolFont= 0,
*noSymbolFont= 0;
const byte o_symbol = 01, // use symbol font
o_grey = 02, // use grey color
o_dot = 04, // mark character with a dot
o_nomove = 010; // draw character without moving cp
static struct outmap {
byte c; // 0 == don't map
byte code;
} OutMap[] = {
0xa4, o_grey, /* 0x00 (0xae???) */
0, 0, /* 0x01 */
0, 0, /* 0x02 */
0, 0, /* 0x03 */
0, 0, /* 0x04 */
0, 0, /* 0x05 */
0, 0, /* 0x06 */
0, 0, /* 0x07 */
0, 0, /* 0x08 */
0xf1, o_symbol|o_grey|o_nomove, /* 0x09 (0xae???) */
0xa6, o_grey, /* 0x0a (0xb6???) */
0, 0, /* 0x0b */
0xdf, o_symbol|o_grey, /* 0x0c */
0xbf, o_symbol|o_grey, /* 0x0d */
0, 0, /* 0x0e */
0, 0, /* 0x0f */
0, 0, /* 0x10 */
0, 0, /* 0x11 */
0, 0, /* 0x12 */
0, 0, /* 0x13 */
0, 0, /* 0x14 */
0, 0, /* 0x15 */
0, 0, /* 0x16 */
0, 0, /* 0x17 */
0, 0, /* 0x18 */
0, 0, /* 0x19 */
0, 0, /* 0x1a */
0, 0, /* 0x1b */
0, 0, /* 0x1c */
0, 0, /* 0x1d */
0, 0, /* 0x1e */
0, 0, /* 0x1f */
};
static inline bool UseSymbolFont(byte c)
{
return c&o_symbol;
}
static inline bool UseGrey(byte c)
{
return gColor && (c&o_grey);
}
static inline bool NoMove(byte c)
{
return c&o_nomove;
}
//---- TextPainter ------------------------------------------------------------
NewMetaImpl(TextPainter, Object, (T(nextFontChange), TP(ps), TP(sp), T(graphicChar)));
TextPainter::TextPainter()
{
linebuf= 0;
}
TextPainter::~TextPainter()
{
SafeDelete(linebuf);
}
void TextPainter::Init(Text *t, int from, int to)
{
line= t->GetLineAccess(&linebuf, from, to);
ps= t->GetParaStyle(from);
nextFontChange= -1;
graphicChar= t->GetMarkChar();
}
int TextPainter::Strip(Text *t, int from, int to)
{
for ( ; to-1 >= from && ((*t)[to-1] == ' ' || (*t)[to-1] == '\t'); to--)
;
return to;
}
int TextPainter::CalcSpace(Text *t, int width, int from, int to,
int &space, int &blanks, int &ntab)
{
int nBlanks, ch;
nBlanks= space= blanks= ntab= 0;
to= Strip(t, from, to);
int w= CalcWidth(t, from, to);
for (int i= from; i < to; i++) {
ch= line[i-from];
switch(ch) {
case '\t':
ntab++;
nBlanks= 0;
break;
case ' ':
nBlanks++;
break;
default:
;
}
}
if (nBlanks) {
blanks= (width - w) % nBlanks;
space= (width - w) / nBlanks;
}
return to;
}
int TextPainter::CalcIndent(Text *t, ParaStyle *p, int at, int &width)
{
int indent= p->GetProperty(eTxtPLeft);
int findent= p->GetProperty(eTxtPFirstIndent);
int rindent= p->GetProperty(eTxtPRight);
if (t->IsParaStart(at))
indent= Math::Max(0, indent+findent);
width= width-indent-rindent;
return indent;
}
bool TextPainter::IsJustified(Text *t, int eol)
{
TxtParaAlign a= (TxtParaAlign)ps->GetProperty(eTxtPAlign);
byte ch= (*t)[eol-1];
return a == eTxtParaJustified && eol != t->Size() && !t->IsBreak(ch);
}
void TextPainter::ShowInvisible(byte ch)
{
Ink *sInk;
Point sPoint;
Font *sFont;
byte code= OutMap[ch].code;
if(code != 0) {
if (UseGrey(code)) {
sInk= GrGetTextInk();
if (invisColor == 0)
invisColor= new_Grey(0.5);
GrSetTextInk(invisColor);
}
if (NoMove(code))
sPoint= GrGetTextPos();
sFont= GrGetFont();
if (UseSymbolFont(code)) {
if (symbolFont == 0)
symbolFont= new_Font(eFontSymbol, 10);
GrSetFont(symbolFont);
}
else {
if (noSymbolFont == 0)
noSymbolFont= new_Font(eFontTimes, 10);
GrSetFont(noSymbolFont);
}
GrDrawChar(OutMap[ch].c);
if (UseGrey(code))
GrSetTextInk(sInk);
if (NoMove(code))
GrTextMoveto(sPoint);
GrSetFont(sFont);
}
}
void TextPainter::SetCharStyle(CharStyle *cs)
{
GrSetFont(cs->GetFont());
GrSetTextInk(cs->GetInk());
}
int TextPainter::FirstCharPos(Text *t, int width, int from, int to)
{
//---- strip trailing whitespace, blank, tab or new line
byte ch= (*t)[to-1];
if (Isspace(ch) || t->IsBreak(ch))
to= Math::Max(0, --to);
TxtParaAlign align= (TxtParaAlign)ps->GetProperty(eTxtPAlign);
switch (align) {
case eTxtParaCenter:
return (width - CalcWidth(t, from, to))/2;
case eTxtParaRight:
return width - CalcWidth(t, from, to);
}
return 0;
}
int TextPainter::CalcWidth(Text *t, int from, int to)
{
int w= 0, ch, d;
int indent= CalcIndent(t, ps, from, d);
nextFontChange= t->GetNextFontChange(from, sp);
for (int i= from; i < to; i++) {
TestFontChange(t, i, sp);
ch= line[i-from];
if (ch == '\t')
w+= CalcTabWidth(t, ps, w+indent, i);
else {
if (TestVisualMark(t, i, ch))
w+= t->GetVisualMarkAt(i)->GetExtent().x;
else
w+= sp->GetFont()->Width(ch);
}
}
return w;
}
void TextPainter::Draw(Text *t, Point p, int from, int to,
Rectangle lr, Rectangle clip, bool invis)
{
register byte ch;
int ntab= 0, tabw, longBlanks= 0, addSpace= 0, seenTabs= 0;
Point left= p;
int w= lr.extent.x;
Init(t, from, to);
bool isJust= IsJustified(t, to);
int indent= CalcIndent(t, ps, from, w);
p.x+= FirstCharPos(t, w, from, to) + indent;
if (invis) {
if (ps->GetProperty(eTxtPNoBreak))
ShowNoBreak(p, lr, t, from, to);
if (ps->GetProperty(eTxtPKeepNext))
ShowKeepNext(p, lr, t, from, to);
}
if (Isspace((*t)[to-1]) && !invis)
to= Math::Max(from, --to);
if (isJust)
CalcSpace(t, w, from, to, addSpace, longBlanks, ntab);
nextFontChange= t->GetNextFontChange(from, sp);
SetCharStyle(sp);
GrTextMoveto(p);
for (int i= from, nBlanks= 0; i < to; i++) {
ch= line[i-from];
if (invis && !gPrinting && Iscntrl(ch))
ShowInvisible(ch);
if (TestFontChange(t, i, sp))
SetCharStyle(sp);
switch (ch) {
case '\t':
tabw= CalcTabWidth(t, ps, GrGetTextPos().x-left.x, i);
GrTextAdvance(tabw);
seenTabs++;
break;
case ' ':
GrTextAdvance(sp->GetFont()->Width(' '));
if (seenTabs == ntab) {
if (addSpace)
GrTextAdvance(addSpace);
if (nBlanks < longBlanks)
GrTextAdvance(1);
nBlanks++;
}
break;
default:
if (TestVisualMark(t, i, ch)) {
DrawVisualMark(GrGetTextPos(),
t->GetVisualMarkAt(i),
clip,
lr,
invis && !gPrinting
);
nextFontChange= t->GetNextFontChange(i, sp);
SetCharStyle(sp);
} else if (!Iscntrl(ch))
GrDrawChar(ch);
}
}
}
void TextPainter::DrawVisualMark(Point p, VisualMark *vmp, Rectangle clip, Rectangle lr, bool border)
{
p.y-= vmp->Base();
Point tp= GrGetTextPos();
vmp->Draw(p, clip, lr, border);
tp.x += vmp->GetExtent().x;
GrTextMoveto(tp);
}
int TextPainter::Map(Text *t, int from, int to, int stop, int x,
int width, int *posX)
{
register byte ch;
int ntab= 0, longBlanks= 0, addSpace= 0, seenTabs= 0, cx= 0, wx= 0;
Init(t, from, to);
int indent= CalcIndent(t, ps, from, width);
int fx= FirstCharPos(t, width, from, to) + indent;
bool isJust= IsJustified(t, to);
// make new lines at end of line not selectable
ch= (*t)[to-1];
if (to-from != 0 && (t->IsBreak(ch)))
to--;
x-= fx;
if (isJust)
to= CalcSpace(t, width, from, to, addSpace, longBlanks, ntab);
nextFontChange= t->GetNextFontChange(from, sp);
for (int i= from, nBlanks= 0; i < to && i < stop; i++) {
TestFontChange(t, i, sp);
switch (ch= line[i-from]) {
case '\t':
wx= CalcTabWidth(t, ps, cx+indent, i);
seenTabs++;
break;
case ' ':
wx= sp->GetFont()->Width(' ');
if (seenTabs == ntab) {
wx += addSpace;
if (nBlanks < longBlanks)
wx++;
nBlanks++;
}
break;
default:
if (TestVisualMark(t, i,ch))
wx= t->GetVisualMarkAt(i)->GetExtent().x;
else
wx= sp->GetFont()->Width(ch);
break;
}
if (cx + (wx/2) > x)
break;
cx+= wx;
}
if (posX)
*posX= cx+fx;
return i;
}
int TextPainter::GetFormatWidth(Text *t, int at, int width)
{
CalcIndent(t, t->GetParaStyle(at), at, width);
return width;
}
int TextPainter::LineWidth(Text *t, int from, int to)
{
Init(t, from, to);
if (t->IsBreak((*t)[to-1]))
to= Math::Max(0, --to);
return CalcWidth(t, from, to);
}
void TextPainter::LineHeight(Text *t, LineDesc &ld, int start, int end)
{
ps= t->GetParaStyle(start);
int sp= ps->GetProperty(eTxtPSpacing);
int d= sp-ld.lnHeight;
if (d > 0) {
ld.lnHeight+= d;
ld.lnAscent+= d;
}
if (t->IsParaStart(start)) {
int sb= ps->GetProperty(eTxtPSpaceBefore);
ld.lnHeight+= sb;
ld.lnAscent+= sb;
}
if (t->IsParaEnd(end-1)) {
int sa= ps->GetProperty(eTxtPSpaceAfter);
ld.lnHeight+= sa;
}
}
int TextPainter::CalcTabWidth(Text *t, ParaStyle *p, int x, int at)
{
const ParaTabs &tabs= ps->GetTabs();
int indent= p->GetProperty(eTxtPLeft);
TxtParaAlign align= (TxtParaAlign)p->GetProperty(eTxtPAlign);
int tx, w= 0;
// tabs are only interpreted if text is left aligned
if (align != eTxtParaLeft && align != eTxtParaJustified)
return 0;
for(int i= 0; i < tabs.ntabs; i++) {
tx= tabs.stops[i].x;
if (tx > x) {
// indent is an implizit tab stop (flush left)
if (indent > x)
return indent-x;
else
switch(tabs.stops[i].kind) {
case eTxtTLeft:
return tx-x;
case eTxtTRight:
w= TabColWidth(t, at, "\t");
return (Math::Max(0, tx-x-w));
case eTxtTCenter:
w= TabColWidth(t, at, "\t");
return (Math::Max(0, tx-x-(w/2)));
case eTxtTDecimal:
w= TabColWidth(t, at, "\t.");
return (Math::Max(0, tx-x-w));
}
}
}
// default tabs
int tw= t->GetDefTab();
if (indent > x)
return indent-x;
if (tw > 0)
return (((x / tw)+1) * tw - x);
return 0;
}
int TextPainter::TabColWidth(Text *t, int start, char *stops)
{
int w= 0, wn, ch;
AutoTextIter next(t, start+1);
while(ch= next(&wn))
if (ch == cEOT || strchr(stops, ch) != 0 || Text::IsBreak(ch))
break;
else
w+= wn;
return w;
}
int TextPainter::Tabulate(Text *t, int x, int at, int lineStart)
{
int w;
ps= t->GetParaStyle(at);
int indent= CalcIndent(t, ps, lineStart, w);
return CalcTabWidth(t, ps, x+indent, at);
}
void TextPainter::ShowNoBreak(Point, Rectangle, Text *, int, int)
{
}
void TextPainter::ShowKeepNext(Point, Rectangle, Text *, int, int)
{
}